<script lang="ts" setup>
import { apiRole, apiUser } from "@/api/sys";
import { useMessage } from "@/hooks/web/use-message";
import { UserStatus, type Form, type UserInfo, type RoleInfo } from "@/models";
import { reactive, ref } from "vue";
import type { VxeModalInstance, VxeModalProps, VxeFormInstance, VxeFormProps, VxeModalListeners } from "vxe-table";
import Avatar from "~icons/ep/avatar";
import Checked from "~icons/ep/checked";
import Tools from "~icons/ep/tools";
import Operation from "~icons/ep/operation";
import { enum2options } from "@/utils";
import ListPicker from "@/components/list-picker.vue";
import MenuPicker from "@/components/menu-picker.vue";

//#region [state]
type PageState = { title: string; show: boolean; step: number; roles: RoleInfo[]; menuIds: number[]; current?: RoleInfo; value?: UserInfo };
const page = reactive<PageState>({ title: "新增用户", show: false, step: 0, roles: [], menuIds: [] });
const emit = defineEmits<{ (event: "onsaved", value?: Nullable<number>): void }>();
const { createMessage } = useMessage();
const { 正常 } = UserStatus;
//#endregion

//#region [modal]
const modalRef = ref<VxeModalInstance>();
const modalProps = reactive<VxeModalProps>({
  resize: true,
  destroyOnClose: true,
  escClosable: true,
  showFooter: true,
  width: 900,
  height: 600,
  position: { top: window.innerHeight * 0.2 },
});
const modalEvents: VxeModalListeners = {
  hide() {
    page.title = "新增用户";
    page.value = undefined;
    page.step = 0;
    formData.value = { uid: "", pwd: "", name: "", loginTimes: 0, status: 正常 };
  },
};
//#endregion

//#region [form]
const statusOptions = enum2options(UserStatus);
const formRef = ref<VxeFormInstance>();
const formData = ref<Form<UserInfo>>({ uid: "", pwd: "", name: "", loginTimes: 0, status: 正常 });
const formProps = reactive<VxeFormProps<Form<UserInfo>>>({
  titleAlign: "right",
  titleWidth: 100,
  span: 24,
  items: [
    { field: "uid", title: "用户名", itemRender: { name: "$input", props: { placeholder: "请输入用户名" } } },
    { field: "name", title: "显示名", itemRender: { name: "$input", props: { placeholder: "请输入姓名" } } },
    { field: "email", title: "邮箱", itemRender: { name: "$input", props: { placeholder: "请输入邮箱" } } },
    { field: "pwd", title: "密码", slots: { default: "field_pwd" } },
    { field: "status", title: "状态", itemRender: { name: "$radio", options: statusOptions } },
  ],
  rules: {
    uid: [
      { required: true, message: "用户名不能为空" },
      { min: 5, max: 100, message: "用户名长度为5~100个字符" },
    ],
    pwd: [
      {
        validator({ itemValue }) {
          if (!page.value && !itemValue) {
            return new Error("密码不能为空");
          }
        },
      },
    ],
    name: [
      { required: true, message: "显示名不能为空" },
      { max: 255, message: "显示名长度不能超过255个字符" },
    ],
    status: [{ required: true }],
  },
});
//#endregion

//#region [action]
async function open(value?: UserInfo) {
  loadRoles();

  if (value) {
    page.title = "编辑用户";
    const response = await apiUser.findById<UserInfo>(value.id);
    if (!response.value) {
      createMessage("warning", "未找到用户，可能已经删除。");
      return;
    }
    page.value = response.value;
    formData.value = response.value;
    formData.value.roleIds = response.value.roles?.map((r) => r.id);
  }

  page.show = true;
}
async function next(delta: number) {
  if (delta > 0) {
    const errMap = await formRef.value?.validate();
    if (errMap) return;
  }

  page.step += delta;
}
async function save() {
  const errMap = await formRef.value?.validate();
  if (!errMap) {
    let result;
    if (page.value) {
      result = await apiUser.edit<number>(page.value.id, formData);
    } else {
      result = await apiUser.add<number>(formData);
    }
    if (result) {
      emit("onsaved", result.value);
      close();
    }
  }
}
function close() {
  page.show = false;
}
async function loadRoles() {
  const response = await apiRole.find<RoleInfo>();
  const roles: RoleInfo[] = [];
  const now = new Date();
  // for (let i = 101; i < 121; i++) roles.push({ id: i, code: "r" + i, name: "r" + i, description: "r" + i, createAt: now, createBy: 0, createUser: "" });
  page.roles = (response.value || []).concat(roles);
}
async function handleLink(current: RoleInfo) {
  page.current = current;
  if (!current.menuIds || !current.menuIds.length) {
    const response = await apiRole.findById<RoleInfo>(current.id);
    if (response.value) {
      const menuIds = response.value.menus?.map((m) => m.id);
      current.menuIds = menuIds;
      page.menuIds = menuIds || [];
    }
  } else {
    page.menuIds = current.menuIds;
  }
}
//#endregion

defineExpose({ open });
</script>

<template>
  <vxe-modal ref="modalRef" v-model="page.show" :="modalProps" @="modalEvents">
    <template #title>{{ page.title }}</template>
    <template #default>
      <div class="user-guide">
        <el-steps :active="page.step" process-status="finish" finish-status="success" simple>
          <el-step title="基本信息" :icon="Avatar" />
          <el-step title="角色配置" :icon="Checked" />
          <el-step title="数据权限" :icon="Tools" />
          <el-step title="特殊权限" :icon="Operation" />
        </el-steps>
        <el-tabs class="tabs-help" v-model="page.step">
          <el-tab-pane :name="0">
            <el-text type="info" size="small">第一步：用户的基本信息，新用户需输入初始密码。</el-text>
          </el-tab-pane>
          <el-tab-pane :name="1">
            <el-text type="info" size="small">第二步：请根据实际业务情况，为用户分配角色。点击角色名查看角色详情。</el-text>
          </el-tab-pane>
          <el-tab-pane :name="2">
            <el-text type="info" size="small">第三步：用户的每个角色均包含业务对象的管理权限，请为每个角色分配每个业务对象的数据管理范围。</el-text>
          </el-tab-pane>
          <el-tab-pane :name="3">
            <el-text type="info" size="small">第四步：为用户直接授予系统功能和对象管理权限。</el-text>
          </el-tab-pane>
        </el-tabs>
        <el-tabs class="tabs-panel" v-model="page.step">
          <el-tab-pane :name="0">
            <vxe-form ref="formRef" :="formProps" :data="formData">
              <template #field_pwd="{ data }">
                <vxe-input type="password" v-model="data.pwd" placeholder="请输入密码" />
              </template>
            </vxe-form>
          </el-tab-pane>
          <el-tab-pane :name="1" class="h-full">
            <el-row class="h-full">
              <el-col :span="6" class="h-full">
                <list-picker v-model="formData.roleIds" :list="page.roles" @link="handleLink" />
              </el-col>
              <el-col :span="18" class="h-full right" v-show="!!page.current">
                <div class="intro">{{ page.current?.description }}</div>
                <menu-picker v-model="page.menuIds" :readonly="true" />
              </el-col>
            </el-row>
          </el-tab-pane>
          <el-tab-pane :name="2"><p>根据实际业务，按需构建</p></el-tab-pane>
          <el-tab-pane :name="3"><p>根据实际业务，按需构建</p></el-tab-pane>
        </el-tabs>
      </div>
    </template>
    <template #footer>
      <el-button type="primary" v-show="page.step > 0" @click="next(-1)">上一步</el-button>
      <el-button type="primary" v-show="page.step < 3" @click="next(1)">下一步</el-button>
      <el-button type="warning" v-show="page.step === 3" @click="save">保存</el-button>
      <el-button @click="close">取消</el-button>
    </template>
  </vxe-modal>
</template>

<style lang="scss" scoped>
.user-guide {
  display: flex;
  flex-direction: column;
  gap: 5px;
  height: 100%;

  :deep(.el-tabs__header) {
    display: none;
  }

  .tabs-help {
    .el-tab-pane {
      border-radius: var(--vxe-border-radius);
      background-color: var(--el-fill-color-light);
      padding: 5px 10px;
    }
  }

  .tabs-panel {
    position: relative;
    flex: auto;
    overflow-y: auto;

    :deep(.el-tabs__content) {
      height: 100%;

      // step 1
      .vxe-form {
        border-radius: var(--vxe-border-radius);
        background-color: transparent;
      }

      // step 2
      .right {
        padding: 0px 10px;
        height: 100%;
        overflow-x: hidden;
        overflow-y: auto;

        .intro {
          margin-bottom: 5px;
          border: 1px solid var(--vxe-input-border-color);
          border-radius: var(--vxe-border-radius);
          padding: 5px 10px;
          text-indent: 2em;
        }
      }
    }
  }
}
</style>
